const querystring = {
	stringify(obj) {
		let arr = []
		for (let key in obj) {
			arr.push(`${key}=${obj[key]}`)
		}
		return arr.join('&');
	},
	parse(str) {
		let obj = {}
		str.split('&').forEach(str => {
			let arr = str.split('=');
			let key = arr.shift();
			let value = arr.join('=');
			obj[key] = value;
		})
		return obj;
	}
}
export default function ajax({
	//超时时间
	timeout,
	//请求拦截器
	requestIntercept,
	//响应拦截器
	responseIntercept,
	//防抖时间间隔
	debounceTime = 200,
	//是否开启防抖
	isDebounce = true,
	//headers默认内容
	defaultHeaders = {},
	//默认方法
	defaultMethod = 'get',
	//默认请求协议
	defaultType = 'json',
	//基准url
	baseURL = ''
} = {}) {
	//处理响应数据
	async function doResponse(data, cacheData) {
		// fetch中会得到promise对象
		data = await data;
		//如果存在响应拦截器
		if (typeof(responseIntercept) === 'function') {
			//返回的结果为最终数据，或者不返回，则继续执行
			let result = await responseIntercept(data);
			//如果有返回结果
			if (result !== undefined) data = result;
			// 返回为假，则终止执行
			if (result === false) return;
		}
		//服务器响应成功
		cacheData.value = data;
		//调用所有的缓存中的回调
		cacheData.cbs.forEach(cb => cb(data))
	}
	/******************************
	 * 设置请求的缓存
	 * isCache:true即开启缓存
	 ******************************/
	const cache = {};

	function setCache(url, method, param, isCache = true, cb) {
		//将url，method，param完全相同的接口判定为相同的接口
		let key = `${url.toLowerCase()}_${method.toLowerCase()}_${JSON.stringify(param)}`;
		if (isCache) {
			//需要缓存缓存
			if (cache[key]) {
				//判断结果是否已经产生
				if (Reflect.has(cache[key], 'value')) {
					//已经有了结果，直接告知结果
					cb(cache[key].value)
				} else {
					//还没有结果，放入回调，等有结果再通知
					cache[key].cbs.push(cb);
				}
				return { state: false, cacheData: cache[key] };
			} else {
				cache[key] = { cbs: [cb] };
				//等待固定的时间后清除
				let timer = setTimeout(() => {
					clearTimeout(timer)
					delete cache[key]
				}, debounceTime)
				//需要继续执行
				return { state: true, cacheData: cache[key] };
			}
		} else {
			//不需要缓存
			return {
				state: true,
				//单独控制无缓存，则回调集合中仅当前，单独请求后再调用
				cacheData: { cbs: [cb] }
			};
		}
	}

	// ==================================================
	return (url, {
		method = defaultMethod,
		isCache = isDebounce,
		headers = defaultHeaders
	} = {}, param, type = defaultType) => {
		//构造一个完整的url
		url = baseURL + url;
		//解构出两种参数,query数据走url，body数据走body
		let { query, body, ...other } = param || {};
		if (!query && !body) {
			/******************************************
			 * 如果两者都没有，则为普通传参
			 * 则需要将param分配给query或者body
			 * 分配原则按照method
			 ******************************************/
			if (['post', 'put'].includes(method.toLowerCase())) {
				//分配给body
				body = param;
			} else {
				//分配给query
				query = param;
			}
		}
		//放在url上的键值对类型的参数字符串
		let queryStr = '';
		//url必须构造字符串参数
		if (query) {
			//参数转化为字符串
			queryStr = querystring.stringify(query);
			//判断原url中是否有？
			if (url.includes('?')) {
				url = `${url}&${queryStr}`;
			} else {
				url = `${url}?${queryStr}`;
			}
		}
		//放在body上的键值对类型的参数字符串
		let bodyStr = undefined;
		let contentType = undefined;
		if (body) {
			if (type === 'json') {
				bodyStr = JSON.stringify(body)
				contentType = 'application/json'
			} else if (type === 'text') {
				bodyStr = body;
				contentType = 'application/text'
			} else if (type === 'form') {
				bodyStr = querystring.stringify(body)
				contentType = 'application/x-www-form-urlencoded'
			} else {
				//比如附件
				bodyStr = body;
			}
		}
		//最终完整的头部协议
		if (contentType) {
			Object.assign(headers, { 'Content-type': contentType })
		}
		//正式调用接口，并返回一个promise
		return new Promise((resolve, reject) => {
			const { state, cacheData } = setCache(url, method, param, isCache, resolve);
			if (state) {
				let timer = null;
				if (timeout) {
					timer = setTimeout(() => reject('响应超时'), timeout)
				}
				if (window.fetch) {
					const config = { method, headers };
					//fetch中get请求不允许存在body
					if (['post', 'put', 'delete'].includes(method.toLowerCase())) {
						config.body = bodyStr;
					}
					return fetch(url, config).then(data => {
						doResponse(data.text(), cacheData)
						//最后要结束超时的计时器
					}, reject).finally(() => clearTimeout(timer))
				} else {
					let xhr = null
					//初始化
					if (window.ActiveXObject) {
						xhr = new window.ActiveXObject();
					} else {
						xhr = new window.XMLHttpRequest();
					}
					//打开
					xhr.open(method, url)
					//设置请求头部
					for (let field in headers) {
						xhr.setRequestHeader(field, headers[field])
					}
					//发送
					xhr.send(bodyStr)
					//监听异步响应
					xhr.onreadystatechange = () => {
						if (xhr.readyState === 4) {
							//结束超时的计时器
							clearTimeout(timer)
							if (xhr.status === 200) {
								doResponse(
									resolve(xhr.responseText), cacheData
								);
							} else {
								//服务器响应失败
								reject(xhr.responseText)
							}
						}
					}
				}
			}
		})
	}
}
